﻿/*
* Copyright (c) 2010-2012 Tesla Engine Group
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/


using System;
using System.Windows.Forms;
using Tesla.Core;
using Tesla.Windows.Util;

namespace Tesla.Windows.Core {
    /// <summary>
    /// Host for Windows that are backed by a <see cref="System.Windows.Forms.Form "/> control. This
    /// sets up the application idle callback and runs the form.
    /// </summary>
    public sealed class SWFWindowHost : IWindowHost {
        private Window _window;

        /// <summary>
        /// Idle event when the application is finished processing messages. Usually the update/draw loop is set here.
        /// </summary>
        public event Heartbeat Idle;

        /// <summary>
        /// Gets the window associated with the host.
        /// </summary>
        public Window AssociatedWindow {
            get {
                return _window;
            }
        }

        /// <summary>
        /// Creates a new window host.
        /// </summary>
        /// <param name="window">Window to run the application with</param>
        public SWFWindowHost(Window window) {
            _window = window;
        }

        /// <summary>
        /// Initiates the loop and calls Application.Run(). This will fail if the window is not a primary window.
        /// </summary>
        public void Run() {
            if(_window.IsPrimaryWindow) {
                SWFWindowImplementation impl = _window.Implementation as SWFWindowImplementation;
                if(impl != null) {
                    Form form = impl.RenderControl as Form;
                    Application.Idle += new EventHandler(ApplicationIdle);
                    Application.Run(form);
                } else {
                    throw new InvalidCastException("Expected SWFWindowImplementation as the underlying window implementing for SWFWindowHost");
                }
            } else {
                throw new TeslaException("Window must be a primary window to run from a windows host.");
            }
        }

        /// <summary>
        /// Exits the loop and calls Application.ExitThread(), the window will be disposed.
        /// </summary>
        public void Exit() {
            _window.Dispose();
            Application.ExitThread();
        }

        private void ApplicationIdle(Object sender, EventArgs args) {
            Tesla.Windows.Util.Message msg;
            while(!NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0)) {
                if(Idle != null) {
                    Idle();
                }
            }
        }
    }
}
